package mdata

import (
	"context"
	"gitee.com/dennis-mxx/gcode-common/mcontext"
	"gitee.com/dennis-mxx/gcode-common/mexception"
	"xorm.io/xorm"
)

type xormManager struct {
	group map[string]*xorm.Engine
}

func NewXormManager() *xormManager {
	return &xormManager{map[string]*xorm.Engine{}}
}
func Default() XormHandler {
	return XormManager.Default()
}

func Handler(id string) XormHandler {
	return XormManager.GetHandler(id)
}

func (ew *xormManager) Register(id string, engine *xorm.Engine) {
	ew.group[id] = engine
}
func (ew *xormManager) Default() XormHandler {
	return ew.GetHandler(DEFAULT_ENGINE_ID)
}

func (ew *xormManager) GetHandler(id string) XormHandler {
	if engine := ew.group[id]; engine == nil {
		panic(mexception.ERROR.Msg("database is not init [" + id + "]"))
		return nil
	} else {
		handler := &MtxXormHandler{
			id:     id,
			engine: engine,
		}
		return handler
	}
}

type Entity interface {
	DB() string
	TableName() string
	IdName() string
}

func ToEntity(entity any) Entity {
	if ele, ok := entity.(Entity); ok {
		return ele
	}
	panic("current model is not entity")
}

type XormHandler interface {
	Database() string

	Session(mtx *mcontext.MContext) *xorm.Session

	Engine() *xorm.Engine

	Close() error

	Commit() error

	Rollback() error
}

type MtxXormHandler struct {
	id      string
	engine  *xorm.Engine
	session *xorm.Session
}

func (ew *MtxXormHandler) Database() string {
	return ew.id
}

func (ew *MtxXormHandler) Session(mtx *mcontext.MContext) *xorm.Session {
	if ew.session != nil {
		return ew.session
	}
	ew.session = ew.engine.NewSession().Context(context.WithValue(context.Background(), mcontext.MTX_CONTEXT_KEY, mtx))
	return ew.session
}

func (ew *MtxXormHandler) Engine() *xorm.Engine {
	return ew.engine
}

func (ew *MtxXormHandler) Close() error {
	if ew.session == nil {
		return nil
	}
	return ew.session.Close()
}
func (ew *MtxXormHandler) Commit() error {
	if ew.session == nil {
		return nil
	}
	if ew.session.IsInTx() {
		return ew.session.Commit()
	}
	return nil
}

func (ew *MtxXormHandler) Rollback() error {
	if ew.session == nil {
		return nil
	}
	if ew.session.IsInTx() {
		return ew.session.Rollback()
	}
	return nil
}

func WithContext(dbId string, mtx *mcontext.MContext) XormHandler {
	contextId := XORM_ENGINE_PREFIX + "_" + dbId
	if current := mtx.Value(contextId); current == nil {
		handler := Handler(dbId)
		mtx.Set(contextId, handler)
		return handler
	} else if currentHandler, ok := current.(XormHandler); ok {
		return currentHandler
	} else {
		panic(mexception.ERROR.Msg("[" + contextId + "] is not XormHandler"))
	}
}
